package com.example.hello.views.tracks;

import com.example.hello.*;
import com.example.hello.POJO.AssignmentPOJO;
import com.example.hello.POJO.OrganizationPOJO;
import com.example.hello.POJO.TrackPOJO;
import com.example.hello.POJO.UserPOJO;
import com.example.hello.views.Wireframe1;
import com.example.hello.views.assignments.Assignments;
import com.example.hello.views.organizations.Organization;
import com.example.hello.views.organizations.Organizations;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.VerticalLayout;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectWriter;
import org.codehaus.jackson.type.TypeReference;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class Tracks extends VerticalLayout implements View {

    public static final String NAME = "tracks";

    private static UserPOJO currentUser;
    private static Set<TrackPOJO> tracks = new HashSet<>();

    private VerticalLayout addLayout = new VerticalLayout();
    private VerticalLayout viewLayout = new VerticalLayout();

    private HorizontalLayout add = new HorizontalLayout();
    private BootstrapButton view = new BootstrapButton("View", BootstrapButton.Size.SMALL);
    private BootstrapButton delete = new BootstrapButton("Delete", BootstrapButton.Size.SMALL);

    private StringWrap selectedTrack = new StringWrap();

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent event) {
        currentUser = ((HelloUI) HelloUI.getCurrent()).getUser();
        if (currentUser == null) currentUser = new UserPOJO();
//        tracks = GETTracks("");
//        if (tracks == null) tracks = new HashSet<>();

        add.setVisible(currentUser.isSiteAdmin());
        delete.setVisible(currentUser.isSiteAdmin());
        if (currentUser.isSiteAdmin()) {
            view.setWidth("110px");
        } else {
            view.setWidth("220px");
        }

        /** Redirect to Track View if needed **/
        String[] parameters = event.getParameters().split("/");
        if (!parameters[0].equals("")) {
            TrackPOJO track = Track.GETTrack(parameters[0]);
            if (track != null) {
                Track trackView = new Track(Tracks.NAME + "/" + track.getEncodedName(), track);
                getUI().getNavigator().addView(trackView.NAME, trackView);
                getUI().getNavigator().navigateTo(trackView.NAME);
            } else {
                getUI().getNavigator().navigateTo(NAME);
            }
        }
    }

    public Tracks() {
        setWidth("100%");

        currentUser = ((HelloUI) HelloUI.getCurrent()).getUser();
        if (currentUser == null) currentUser = new UserPOJO();
        tracks = GETTracks("");
        if (tracks == null) tracks = new HashSet<>();
        
        initAdd();
        initDisplay();

        addComponent(addLayout);
        addComponent(viewLayout);
        setComponentAlignment(viewLayout, Alignment.TOP_CENTER);
        setExpandRatio(viewLayout, 1);
    }

    private void initAdd() {
        add.setWidth("800px");
        
        final Heading nameHeading = new Heading("Name", 6);
        final TextField nameField = new TextField();
        final Heading orgHeading = new Heading("Organization", 6);
        final TextField orgField = new TextField();
        final BootstrapButton trackSubmit = new BootstrapButton("Add Track");
        trackSubmit.setWidth("120px");

        trackSubmit.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                Organization.addTrack(
                        Organization.GETOrg(orgField.getEncodedValue()),
                        new TrackPOJO(nameField.getEncodedValue()),
                        true
                );
                getUI().getNavigator().navigateTo(Tracks.NAME);
            }
        });
        TextField.enterKeyHandler(trackSubmit, nameField);
        TextField.enterKeyHandler(trackSubmit, orgField);

        add.addComponents(
                nameHeading, new HSpacer(5), nameField,
                new HSpacer(20),
                orgHeading, new HSpacer(5), orgField,
                new HSpacer(20),
                trackSubmit
        );

        add.setComponentAlignment(nameHeading, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(nameField, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(orgHeading, Alignment.MIDDLE_LEFT);
        add.setComponentAlignment(orgField, Alignment.MIDDLE_LEFT);
        add.setExpandRatio(nameField, 1);
        add.setExpandRatio(orgField, 1);

        addLayout.addComponents(new VSpacer(10), add, new VSpacer(20));
        addLayout.setComponentAlignment(add, Alignment.MIDDLE_CENTER);
        addLayout.setExpandRatio(add, 1);
    }

    private void initDisplay() {
        final ListBox trackList = new ListBox();
        delete.setWidth("110px");

        trackList.setVisibleItems(16);
        for (TrackPOJO track : tracks) trackList.addItem(track.getDecodedName());
        Collections.sort(trackList.getItems());
        if (trackList.getItems().size() != 0) {
            selectedTrack.setString(trackList.getItems().get(0));
        } else {
            view.setEnabled(false);
            delete.setEnabled(false);
        }
        trackList.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                if (event instanceof ListBoxChangeEvent) {
                    selectedTrack.setString(((ListBoxChangeEvent) event).getSelected());
                }
            }
        });
        view.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                getUI().getNavigator().navigateTo(NAME + "/" + selectedTrack.getEncoded());
            }
        });
        delete.addListener(new Listener() {
            @Override
            public void componentEvent(Event event) {
                removeTrack(Track.GETTrack(selectedTrack.getEncoded()));
                getUI().getNavigator().navigateTo(NAME);
            }
        });

        HorizontalLayout buttons = new HorizontalLayout(view, delete);

        // add trackList for display
        viewLayout.addComponents(trackList, buttons);
        viewLayout.setComponentAlignment(trackList, Alignment.TOP_CENTER);
        viewLayout.setComponentAlignment(buttons, Alignment.TOP_CENTER);
    }

    public static Set<TrackPOJO> GETTracks(String query) {
        Set<TrackPOJO> tracks = new HashSet<>();
        try {
            String json = HttpRequest.GET(Tracks.NAME + query);
            ObjectMapper mapper = new ObjectMapper();
            tracks = mapper.readValue(json, new TypeReference<Set<TrackPOJO>>() {
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return tracks;
    }

    public static Set<TrackPOJO> getTracks() {
        return tracks;
    }

    public static void setTracks(Set<TrackPOJO> tracks) {
        Tracks.tracks = tracks;
    }

    public static boolean addTrack(TrackPOJO track) {
        // post a track to get an _id
        if (!HttpRequest.executePost(NAME, track.toJSON())) return false;

        // get the track with _id attached
        track = Track.GETTrack(track.getEncodedName());
        if (!tracks.contains(track)) tracks.add(track);

        // create the View with the track
        Track trackView = new Track(Tracks.NAME + "/" + track.getEncodedName(), track);
        HelloUI.getCurrent().getNavigator().addView(trackView.NAME, trackView);

        return true;
    }

    public static boolean removeTrack(TrackPOJO track) {
        // get all linked resources and update or relocate
        Set<OrganizationPOJO> orgs = Organizations.GETOrganizations("?track=" + track.getEncodedName());
        List<AssignmentPOJO> assignments = Assignments.GETAssignments("?track=" + track.getEncodedName());
        for (OrganizationPOJO org : orgs) {
            if (org.removeTrack(track.getEncodedName())) org.update();
        }
        for (AssignmentPOJO assignment : assignments) {
            assignment.setTrack(AssignmentPOJO.UNASSIGNED);
            assignment.update();
        }

        // delete the track
        HttpRequest.executeDelete(NAME + "/" + track.getEncodedName());
        HelloUI.getCurrent().getNavigator().removeView(NAME + "/" + track.getEncodedName());

        return tracks.remove(track);
    }

    public static boolean hasTrack(TrackPOJO track) {
        return tracks.contains(track);
    }

}